package com.adun.scheduler.xxljob;

import com.adun.scheduler.ISchedulerJob;
import com.adun.scheduler.SchedulerJobManager;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.glue.GlueFactory;
import com.xxl.job.core.handler.impl.MethodJobHandler;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.MethodIntrospector;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * xxl-job任务执行器 定制注册逻辑
 * @author ZDF
 * @date 2025/8/8
 */
@Slf4j
public class DynamicXxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean {

    private static final Logger logger = LoggerFactory.getLogger(DynamicXxlJobSpringExecutor.class);


    // start
    @Override
    public void afterSingletonsInstantiated() {

        // init JobHandler Repository
        /*initJobHandlerRepository(applicationContext);*/

        // init JobHandler Repository (for method)
        initJobHandlerMethodRepository(applicationContext);

        // refresh GlueFactory
        GlueFactory.refreshInstance(1);

        // super start
        try {
            super.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // destroy
    @Override
    public void destroy() {
        log.info("=============================dynamic-xxl-job-scheduler================================");
        super.destroy();
        log.info("=============================dynamic-xxl-job-scheduler================================");
    }

    public void initJobHandlerMethodRepository(ApplicationContext applicationContext) {
        log.info("=============================dynamic-xxl-job-scheduler================================");
        if (applicationContext == null) {
            return;
        }
        List<ISchedulerJob> schedulerJobs = SchedulerJobManager.getSchedulerJobs();
        for (ISchedulerJob schedulerJob : schedulerJobs) {
            Object bean = applicationContext.getBean(schedulerJob.getJobClassType());
            Set<Method> executeMethodSet = MethodIntrospector.selectMethods(schedulerJob.getJobClassType(), new ReflectionUtils.MethodFilter() {
                @Override
                public boolean matches(Method method) {
                    Boolean flag = false;
                    method.setAccessible(true);
                    Parameter[] parameters = method.getParameters();
                    if ("execute".equals(method.getName()) && parameters.length == 0) {
                        flag = true;
                    }
                    return flag;
                }
            });

            if (executeMethodSet.size() > 1) {
                throw new RuntimeException("定时任务类" + schedulerJob.getJobClassType() + "只能有一个无参execute方法");
            }
            Set<Method> initMethodSet = MethodIntrospector.selectMethods(schedulerJob.getJobClassType(), new ReflectionUtils.MethodFilter() {
                @Override
                public boolean matches(Method method) {
                    Boolean flag = false;
                    method.setAccessible(true);
                    Parameter[] parameters = method.getParameters();
                    if ("init".equals(method.getName()) && parameters.length == 0) {
                        flag = true;
                    }
                    return flag;
                }
            });

            if (initMethodSet.size() > 1) {
                throw new RuntimeException("定时任务类" + schedulerJob.getJobClassType() + "只能有一个无参init方法");
            }

            Set<Method> destroyMethodSet = MethodIntrospector.selectMethods(schedulerJob.getJobClassType(), new ReflectionUtils.MethodFilter() {
                @Override
                public boolean matches(Method method) {
                    Boolean flag = false;
                    method.setAccessible(true);
                    Parameter[] parameters = method.getParameters();
                    if ("destroy".equals(method.getName()) && parameters.length == 0) {
                        flag = true;
                    }
                    return flag;
                }
            });

            if (destroyMethodSet.size() > 1) {
                throw new RuntimeException("定时任务类" + schedulerJob.getJobClassType() + "只能有一个无参destroy方法");
            }

            registJobHandler(schedulerJob.getJobName(),
                    new MethodJobHandler(bean, new ArrayList<>(executeMethodSet).get(0),
                            new ArrayList<>(initMethodSet).get(0),
                            new ArrayList<>(destroyMethodSet).get(0)));
            logger.info("xxl-job jobHandlerName:{}, jobHandlerClass:{}", schedulerJob.getJobName(), schedulerJob.getJobClassType().getName());
        }
        log.info("=============================dynamic-xxl-job-scheduler================================");
    }

    // ---------------------- applicationContext ----------------------
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        DynamicXxlJobSpringExecutor.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /*
    BeanDefinitionRegistryPostProcessor
    registry.getBeanDefine()
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        this.registry = registry;
    }
    * */
}
